/* 
 * File:   main.c
 * Author: stoppy
 *
 * Created on 17 marzo 2009, 15.18
 */

#include <stdio.h>
#include <stdlib.h>
#include "mod_utils.h"
#include "mod_error.h"
#include "mod_config.h"
#include "mod_file.h"
#include "superpeer.h"
#include "structures.h"
#include "mod_network.h"
#include "mod_protocol.h"
#include <glib-2.0/glib/gtypes.h>
#include <glib-2.0/glib/glist.h>
#include <glib-2.0/glib/gthread.h>

PeerConfig *pconf;
SpConfig *spconf;
GList* fileRepresentation;
GList* connectedPeer;
GList* listaSP;
GStaticRWLock fileRepresentationLock;
GStaticRWLock connectedPeerLock;
GStaticRWLock listaSPLock;
float globalAva = 1.0;
float localAva = 1.0;
int localLoad = 0;
int nRepliche = 4;

//per usare correttamente questa funzione deve esserci almeno un peer collegato
void calcNewLoad(){

    int i = 0, newLoad=0;
    int nPeer = (int) g_list_length_ts(connectedPeer, &connectedPeerLock);
    struct PEER * ptemp;
    for(i=0;i<nPeer;i++){
        ptemp = (struct PEER *) g_list_get_element_at_ts(connectedPeer, (guint) i, &connectedPeerLock);
        newLoad = newLoad + ptemp->load;
    }
    localLoad = (int)(newLoad/nPeer);
}
//per usare correttamente questa funzione deve esserci almeno un peer collegato
void calcNewLocalAva(){

    int i = 0, newAva=0;
    int nPeer = (int) g_list_length_ts(connectedPeer, &connectedPeerLock);
    struct PEER * ptemp;
    for(i=0;i<nPeer;i++){
        ptemp = (struct PEER *) g_list_get_element_at_ts(connectedPeer, (guint) i, &connectedPeerLock);
        newAva = newAva + ptemp->ava;
    }
    localAva = (newAva/nPeer);

}
void calcNewGlobalAva(){

    int i = 0, newGlobalAva=0;
    int nSP = (int) g_list_length_ts(listaSP, &listaSPLock);
    struct SUPER_PEER * sptemp;
    for(i=0;i<nSP;i++){
        sptemp = (struct SUPER_PEER *) g_list_get_element_at_ts(listaSP, (guint) i, &listaSPLock);
        newGlobalAva = newGlobalAva + sptemp->ava;
    }
    globalAva = (newGlobalAva/nSP);

}
void calcNewNReplicas(int desiredReplicas){
   
    nRepliche = (2*(desiredReplicas))/globalAva;

}
gpointer managePeerRequest(){
    struct sockaddr_in addr;
    int listSD;
    int connSD;
    GThread* thread = NULL;
    gpointer(*functionToExecute) (gpointer data);
    functionToExecute = handleOperation;
    if ((listSD = create_TCP_server_socket(spconf->portlistenpeer, 50, &addr)) < 0) {
        return -1;
    }
    while (1) {
        //metto in attesa che arrivino connessioni
        if ((connSD = accept_connection(&listSD, &addr)) < 0) {
            return -2;
        }
        if ((thread = g_thread_create(functionToExecute, (gpointer) connSD, 0, NULL)) == NULL) {
            return -3;
        }
    }
}
gpointer manageSPRequest(){

    struct sockaddr_in addr;
    int listSD;
    int connSD;
    GThread* thread = NULL;
    gpointer(*functionToExecute) (gpointer data);
    functionToExecute = handleOperation;
    if ((listSD = create_TCP_server_socket(spconf->portlistensp, 50, &addr)) < 0) {
        return -1;
    }
    while (1) {
        //metto in attesa che arrivino connessioni
        if ((connSD = accept_connection(&listSD, &addr)) < 0) {
            return -2;
        }
        if ((thread = g_thread_create(functionToExecute, (gpointer) connSD, 0, NULL)) == NULL) {
            return -3;
        }
    }

}

int main(int argc, char** argv) {
    pconf = loadPeerConfig("peerconfig.conf");
    spconf = loadSuperPeerConfig("superpeerconfig.conf");

    //Lista di strutture FILE_IN_SUPER_PEER
    fileRepresentation = NULL;
    //Lista dei peer connessi
    connectedPeer = NULL;

    listaSP = NULL;

    //inizializzazione dei thread
    if(!g_thread_supported())
    {
        g_thread_init(NULL);
    }

    //inizializzazione dei lock sulle list
    g_static_rw_lock_init(&connectedPeerLock);
    g_static_rw_lock_init(&fileRepresentationLock);
    g_static_rw_lock_init(&listaSPLock);

    //a questo punto è importante inizializzare correttamente la lista dei SP
    //poniamo il caso che ci siano 2 superpeer
    struct SUPER_PEER * sp1 = calloc(1,sizeof(struct SUPER_PEER));
    struct SUPER_PEER * sp2 = calloc(1,sizeof(struct SUPER_PEER));

    strcpy(sp1->addr,"127.0.0.1");
    sp1->port=5351;
    sp1->ava=1.0;
    sp1->load=0;
    strcpy(sp1->hash,"sonolhashdelprimosuperpeersonolh");
    sp1->hash[32]='\0';

    strcpy(sp2->addr,"127.0.0.1");
    sp2->port = 5352;
    sp2->ava=1.0;
    sp2->load=0;
    strcpy(sp2->hash,"sonolhashdelsecondosuperpeersono");
    sp2->hash[32]='\0';

    //il primo elemento della lista è relativo allo stesso SP

    //caso di SP1

    listaSP = g_list_insert_inqueue_ts(listaSP, (gpointer)sp1 , &listaSPLock);
    listaSP = g_list_insert_inqueue_ts(listaSP, (gpointer)sp2 , &listaSPLock);

    //caso di SP2

   // listaSP = g_list_insert_inqueue_ts(listaSP, (gpointer)sp2 , &listaSPLock);
   // listaSP = g_list_insert_inqueue_ts(listaSP, (gpointer)sp1 , &listaSPLock);

    GThread* thread1 = NULL;
    GThread* thread2 = NULL;
    gpointer(*functionToExecute1)  (gpointer data);
    functionToExecute1 = manageSPRequest;
    gpointer(*functionToExecute2)  (gpointer data);
    functionToExecute2 = managePeerRequest;
    
    
    if ((thread1 = g_thread_create(functionToExecute1, NULL, 1, NULL)) == NULL) {
            return -3;
    }
    if ((thread2 = g_thread_create(functionToExecute2, NULL, 1, NULL)) == NULL) {
            return -3;
    }

    g_thread_join(thread1);
    g_thread_join(thread2);
   /* struct sockaddr_in addr;
    int listSD;
    int connSD;
    GThread* thread = NULL;
    gpointer(*functionToExecute) (gpointer data);
    functionToExecute = handleOperation;
    if ((listSD = create_TCP_server_socket(spconf->portlistenpeer, 50, &addr)) < 0) {
        return -1;
    }
    while (1) {
        //metto in attesa che arrivino connessioni
        if ((connSD = accept_connection(&listSD, &addr)) < 0) {
            return -2;
        }
        if ((thread = g_thread_create(functionToExecute, (gpointer) connSD, 0, NULL)) == NULL) {
            return -3;
        }
    }*/

    return (EXIT_SUCCESS);

}

